﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using Xceed.Wpf.Toolkit;

namespace OpenSearchExplorer
{
    /// <summary>
    /// Interaction logic for TemplateCompletionPage.xaml
    /// </summary>
    public partial class TemplateCompletionPage : Page
    {
        private OpenSearch.Osdd.Url url = null;

        public TemplateCompletionPage()
        {
            InitializeComponent();
        }

        public void setUrl(OpenSearch.Osdd.Url url)
        {
            this.url = url;
            headerBlock.Inlines.Add(new Run("MIME type: " + url.MimeType + Environment.NewLine));
            List<OpenSearch.TemplateParameter> templateParameters = url.Template.TemplateParameters.ToList<OpenSearch.TemplateParameter>();
            foreach (OpenSearch.TemplateParameter templateParameter in templateParameters)
            {
                switch (templateParameter.Kind)
                {
                    case OpenSearch.TemplateParameterKind.Literal:
                        addLiteral(templateParameter);
                        break;
                    case OpenSearch.TemplateParameterKind.RequiredSubstitution:
                        addRequiredSubstitution(templateParameter);
                        break;
                    case OpenSearch.TemplateParameterKind.OptionalSubstitution:
                        addOptionalSubstitution(templateParameter);
                        break;
                    default:
                        break;
                }
            }
        }

        private void addOptionalSubstitution(OpenSearch.TemplateParameter templateParameter)
        {
            AddEmptyRow();
            AddRowLabel(templateParameter.Name);
            addOptionalSubstitutionValue(templateParameter);
        }

        private void addRequiredSubstitution(OpenSearch.TemplateParameter templateParameter)
        {
            AddEmptyRow();
            AddRowLabel(templateParameter.Name);
            addRequiredSubstitutionValue(templateParameter);
        }

        private void addOptionalSubstitutionValue(OpenSearch.TemplateParameter templateParameter)
        {
            if (isDateTimeParameter(templateParameter))
            {
                addDateTimePicker(templateParameter);
            }
            else
            {
                TextBox box = createEmptyTextBox();
                CueBannerService.SetCueBanner(box, createCueText(templateParameter));
            }
        }

        private static string createCueText(OpenSearch.TemplateParameter templateParameter)
        {
            return templateParameter.SubstitutionParameterValue.Parameter + " (" + templateParameter.SubstitutionParameterValue.Namespace + ")";
        }

        private void addRequiredSubstitutionValue(OpenSearch.TemplateParameter templateParameter)
        {
            if (isDateTimeParameter(templateParameter)                )
            {
                addDateTimePicker(templateParameter);
            }
            else
            {
                // No special case
                TextBox box = createEmptyTextBox();
                CueBannerService.SetCueBanner(box, createCueText(templateParameter));
                setBoxFormatInvalid(box);
                box.TextChanged += new TextChangedEventHandler(box_TextChanged);
            }
        }

        private static bool isDateTimeParameter(OpenSearch.TemplateParameter templateParameter)
        {
            return (templateParameter.SubstitutionParameterValue.Namespace == OpenSearch.Constants.NSOpenSearchTime) &&
                            ((templateParameter.SubstitutionParameterValue.Parameter == "start") ||
                             (templateParameter.SubstitutionParameterValue.Parameter == "end"));
        }

        private void addDateTimePicker(OpenSearch.TemplateParameter templateParameter)
        {
            DateTimePicker datePicker = new DateTimePicker();
            datePicker.TextAlignment = TextAlignment.Left;
            CueBannerService.SetCueBanner(datePicker, createCueText(templateParameter));
            Grid.SetColumn(datePicker, 1);
            int rowNumber = templateGrid.RowDefinitions.Count - 1;
            Grid.SetRow(datePicker, rowNumber);
            templateGrid.Children.Add(datePicker);
        }

        private void setBoxFormatInvalid(TextBox box)
        {
            box.BorderBrush = new SolidColorBrush(Colors.Red);
        }

        private static void setBoxFormatValid(TextBox box)
        {
            box.ClearValue(TextBox.BorderBrushProperty);
        }

        private void box_TextChanged(object sender, TextChangedEventArgs e)
        {
            TextBox box = sender as TextBox;
            if (box == null)
            {
                return;
            }
            if (box.Text.Length != 0)
            {
                setBoxFormatValid(box);
            }
            else
            {
                setBoxFormatInvalid(box);
            }
        }

        private TextBox createEmptyTextBox()
        {
            TextBox box = new TextBox();
            box.BorderThickness = new System.Windows.Thickness(1.001); // Crude hack to prevent colour change when this box has focus.
            box.Text = "";
            Grid.SetColumn(box, 1);
            int rowNumber = templateGrid.RowDefinitions.Count - 1;
            Grid.SetRow(box, rowNumber);
            templateGrid.Children.Add(box);
            return box;
        }

        private void addLiteral(OpenSearch.TemplateParameter templateParameter)
        {
            AddEmptyRow();
            AddRowLabel(templateParameter.Name);
            AddLiteralValue(templateParameter.ParameterValue);
        }

        private void AddLiteralValue(string templateParameterValue)
        {
            TextBox literalValueBox = new TextBox();
            literalValueBox.Text = templateParameterValue;
            literalValueBox.IsEnabled = false;
            Grid.SetColumn(literalValueBox, 1);
            int rowNumber = templateGrid.RowDefinitions.Count - 1;
            Grid.SetRow(literalValueBox, rowNumber);
            templateGrid.Children.Add(literalValueBox);
        }

        private void AddRowLabel(string templateParameterName)
        {
            TextBlock label = new TextBlock(new Bold(new Run(templateParameterName + "  ")));
            Grid.SetColumn(label, 0);
            int rowNumber = templateGrid.RowDefinitions.Count - 1;
            Grid.SetRow(label, rowNumber);
            templateGrid.Children.Add(label);
        }

        private void AddEmptyRow()
        {
            RowDefinition literalRow = new RowDefinition();
            literalRow.Height = new GridLength(1.0, GridUnitType.Auto);
            templateGrid.RowDefinitions.Add(literalRow);
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            OpenSearch.Template template = url.Template;
            List<OpenSearch.TemplateParameter> parameters = template.TemplateParameters.ToList<OpenSearch.TemplateParameter>();
            foreach (OpenSearch.TemplateParameter parameter in parameters)
            {
                if (parameter.Kind != OpenSearch.TemplateParameterKind.Literal)
                {
                    parameter.ParameterValue = lookupParameterValueInGrid(parameter); 
                }
            }
            Uri query = template.InstantiateTemplate();
            runQuery(query);
        }

        private string lookupParameterValueInGrid(OpenSearch.TemplateParameter parameter)
        {
            foreach (UIElement uiElement in templateGrid.Children)
            {
                // TODO: this is gross
                TextBlock textBlock = uiElement as TextBlock;
                if (textBlock == null)
                {
                    continue;
                }
                Bold topLevelInline = textBlock.Inlines.FirstInline as Bold;
                Run runInline = topLevelInline.Inlines.FirstInline as Run;
                string textBlockText = runInline.Text.Trim();

                if ((Grid.GetColumn(uiElement) == 0) && (textBlockText == parameter.Name))
                {
                    int targetRow = Grid.GetRow(uiElement);
                    string associatedParameterValue = lookupValueInGrid(targetRow, 1);
                    return associatedParameterValue;
                }
            }
            return null;
        }

        private string lookupValueInGrid(int targetRow, int targetColumn)
        {
            foreach (UIElement uiElement in templateGrid.Children)
            {
                if ((Grid.GetColumn(uiElement) == targetColumn) && (Grid.GetRow(uiElement) == targetRow))
                {
                    if (uiElement is TextBox)
                    {
                        TextBox box = uiElement as TextBox;
                        return box.Text;
                    }
                    else
                        if (uiElement is Xceed.Wpf.Toolkit.DateTimePicker)
                        {
                            Xceed.Wpf.Toolkit.DateTimePicker dateTimePicker = uiElement as Xceed.Wpf.Toolkit.DateTimePicker;
                            if (dateTimePicker.Value == null)
                            {
                                return "";
                            }
                            DateTime dateTime = (System.DateTime)dateTimePicker.Value;
                            // TODO: consider making this a static method in OpenSearchNet
                            return System.Xml.XmlConvert.ToString(dateTime, System.Xml.XmlDateTimeSerializationMode.RoundtripKind);
                        }
                }
            }
            return null;
        }

        private void runQuery(Uri query)
        {
            QueryResultsPage queryResultsPage = new QueryResultsPage(query, url.MimeType);
            this.NavigationService.Navigate(queryResultsPage);
        }
    }
}
;